#include <zconf.h>

#include "FHE.h"
#include "EncryptedArray.h"
#include "Service.h"

FHEcontext *context1;
EncryptedArray *ea1;
FHESecKey *secretKey1;

long w = 64;                // Hamming weight of secret key

string strRe;
bool isinit = false;

void init() {
    //cout << " init  :start" << endl;
    long m = 2, p = 715827883, r = 2;   // Native plaintext space(本机明文空间)
    long L = 16;                // Levels
    long c = 3;                 // Columns in key switching matrix
    context1 = new FHEcontext(m, p, r);    // 初始化上下文, 《非常慢》
    buildModChain(*context1, L, c);   //修改上下文，增加模链的素数
    ZZX G = context1->alMod.getFactorsOverZZ()[0];
    ea1 = new EncryptedArray(*context1, G);  //constuct是一个加密的数组对象ea , 与给定的上下文和多项式G相关联
    secretKey1 = new FHESecKey(*context1);   // 构造与上下文相关的秘密关键结构
    secretKey1->GenSecKey(w);  //实际上生成的秘钥
    addSome1DMatrices(*secretKey1); //计算我们需要的键交换矩阵
    isinit = true;
   // cout << " init  :end" << endl;
}

//加密
const char *encrypt(long text) {
    if (!isinit) init();
    //cout << "encrypt" << endl;
    const FHEPubKey &publicKey1 = *secretKey1;
    Ctxt ct2_p(publicKey1);
    vector<long> v2;
    v2.push_back(text);

    ea1->encrypt(ct2_p, publicKey1, v2);
    std::stringstream stream;
    stream << ct2_p << endl;
    strRe = stream.str();
     char *pc = (char *) strRe.c_str();
    // cout << pc << endl;
    return pc;
}


//解密
long decrypt(const char *text) {
    const FHEPubKey &publicKey = *secretKey1;
   // cout << "decrypt" << endl;
    if (!isinit) init();
    vector<long> v2_j;
    Ctxt ct2_p(publicKey);

    std::stringstream stream;
    stream << text;
    stream >> ct2_p;
    ea1->decrypt(ct2_p, *secretKey1, v2_j);
    return v2_j[0];
}


//加法
const char *add(const char *ptext_1, const char *ptext_2) {
    const FHEPubKey &publicKey = *secretKey1; // FHESecKey是FHEPubKey的一个子类

    if (!isinit) init();
    vector<long> v2_j;
    Ctxt ct1_p(publicKey);
    Ctxt ct2_p(publicKey);

    std::stringstream stream1;
    stream1 << ptext_1;
    stream1 >> ct1_p;

    std::stringstream stream2;
    stream2 << ptext_2;
    stream2 >> ct2_p;

    ct1_p.addCtxt(ct2_p, false);

    std::stringstream stream;
    stream << ct1_p << endl;
    strRe = stream.str();
    const char *pc = (strRe.data());
    return pc;
}


//乘法
const char *mul(const char *ptext_1, const char *ptext_2) {
    const FHEPubKey &publicKey = *secretKey1; // FHESecKey是FHEPubKey的一个子类
    if (!isinit) init();
    vector<long> v2_j;
    Ctxt ct1_p(publicKey);
    Ctxt ct2_p(publicKey);

    std::stringstream stream1;
    stream1 << ptext_1;
    stream1 >> ct1_p;

    std::stringstream stream2;
    stream2 << ptext_2;
    stream2 >> ct2_p;

    ct1_p.multiplyBy(ct2_p);

    std::stringstream stream;
    stream << ct1_p << endl;
    strRe = stream.str();
    const char *pc = (strRe.data());
    return pc;

}
